package simsimdev;

import static simsim.core.Simulation.rg;

import java.util.HashSet;
import java.util.Set;

import simsim.core.AbstractNode;
import simsim.core.EndPoint;
import simsim.core.Message;
import simsim.core.PeriodicTask;
import simsim.gui.canvas.RGB;
import simsim.utils.RandomList;
import simsimdev.NodeDB;
import simsimdev.msgs.ExtendedMessageHandler;
import simsimdev.msgs.SeedExchange;
import simsimdev.msgs.ValueExchange;

import umontreal.iro.lecuyer.probdist.TruncatedDist;
import umontreal.iro.lecuyer.probdist.WeibullDist;
import umontreal.iro.lecuyer.randvar.RandomVariateGen;
import umontreal.iro.lecuyer.rng.MRG32k3a;

public class Node extends AbstractNode implements ExtendedMessageHandler {

	private RandomList<EndPoint> knownNodes = new RandomList<EndPoint>();
	private int maxSeed;
	private int function;
	double ownValue;
	boolean infected = false;
	double value;
	
	public Node(int function, int maxSeed) {
		super();
		NodeDB.store( this);
		this.maxSeed = maxSeed;
		this.function = function;
	}

	public void infect() {
		infected = true ;
		setColor( RGB.RED ) ;
	}
	
	public void init() {
		setColor( RGB.GREEN ) ;
		knownNodes.addAll( NodeDB.randomEndPoints(this, maxSeed));
		ownValue = value = new RandomVariateGen(new MRG32k3a(), new TruncatedDist( new WeibullDist( 1.8, 1.5e-6, 0 ), 0, 1000000)).nextDouble();
		
		new PeriodicTask(this, rg.nextDouble(), 1.0) {
			public void run() {
				udpSend( knownNodes.randomElement(), new ValueExchange(value));
			}
		};
		
		new PeriodicTask(this, rg.nextDouble(), 2.0) {
			public void run() {
				udpSend( knownNodes.randomElement(), new SeedExchange(knownNodes));
			}
		};

	}

	public void onReceive(EndPoint src, ValueExchange m) {
			if(m.value < value){
				if(function == 2) value = m.value;
				else if(function == 1) udpSend(src, new ValueExchange(value));
			}else if(m.value > value){
				if(function == 2) udpSend(src, new ValueExchange(value));
				else if(function == 1) value = m.value;
			}
	}

	public void onSendFailure( EndPoint dst, Message m ) {
		knownNodes.remove( dst ) ;
	}
	
	public void onReceive(EndPoint src, SeedExchange m) {
		Set<EndPoint> x = new HashSet<EndPoint>( knownNodes);
		x.add(src);
		x.addAll(m.seeds);
		knownNodes = new RandomList<EndPoint>(x);

		while (knownNodes.size() > maxSeed)
			knownNodes.removeRandomElement();
	}
}
